﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;

namespace DLULearningNetworkModel
{
    public class AccountValidation
    {
        [Required(AllowEmptyStrings = false, ErrorMessage = "Vui lòng điền tên của bạn.")]
        public string FirstName_s { get; set; }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Vui lòng điền họ của bạn.")]
        public string LastName_s { get; set; }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Vui lòng nhập địa chỉ email.")]
        [RegularExpression(@"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@"
             + @"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
				        [0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
             + @"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
				        [0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
             + @"([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})$", ErrorMessage = "Địa chỉ email không chính xác.")]
        public string Email_s { get; set; }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Hãy chọn giới tính của bạn.")]
        public bool Sex_b { get; set; }

        [Required(ErrorMessage = "Hãy chọn ngày tháng năm sinh.")]
        public DateTime DateOfBirth_dt { get; set; }

        [Required(ErrorMessage = "Vui lòng nhập password.")]
        [Range(8, 16, ErrorMessage = "Mật khẩu phải có từ 8 đến 16 ký tự.")]
        public string Password_s { get; set; }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Vui lòng nhập nickname.")]
        [Range(4, 16, ErrorMessage = "Nickname phải có từ 4 đến 16 ký tự.")]
        public string Nickname_s { get; set; }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Vui lòng nhập câu trả lời.")]
        [Range(1, 50, ErrorMessage = "Câu trả lời quá dài.")]
        public string Answer_s { get; set; }
    }

    public partial class Account
    {
        public static Account Single(string email, string password)
        {
            using (var db = new DLULNEntities())
            {
                return db.Accounts.Where(acc => acc.Email_s.ToLower().CompareTo(email.ToLower()) == 0 && 
                    acc.Password_s.CompareTo(password) == 0).FirstOrDefault();
            }
        }

        public static Account UpdateBasicInfo(Account account)
        {
            try
            {
                using (DLULNEntities db = new DLULNEntities())
                {
                    Account existAccount = db.Accounts.SingleOrDefault(a => a.AccountID_u == account.AccountID_u);
                    if (existAccount != null)
                    {
                        existAccount.FirstName_s = account.FirstName_s;
                        existAccount.LastName_s = account.LastName_s;
                        existAccount.DateOfBirth_dt = account.DateOfBirth_dt;
                        existAccount.SecurityQuestionID_u = account.SecurityQuestionID_u;
                        existAccount.Answer_s = account.Answer_s;
                        existAccount.Sex_b = account.Sex_b;
                        if (db.SaveChanges() > 0)
                        {
                            return existAccount;
                        }
                    }
                    return null;
                }
            }
            catch 
            {
                return null;   
            }
        }

        public static Account Single(string email, Guid securityQuestionID, string answer)
        {
            using (var db = new DLULNEntities())
            {
                return (from acc in db.Accounts
                        where acc.Email_s.ToLower().CompareTo(email.ToLower()) == 0 && acc.SecurityQuestionID_u == securityQuestionID
                           && acc.Answer_s.ToLower().CompareTo(answer.ToLower()) == 0
                        select acc).FirstOrDefault();
            }
        }

        public static Account Single(string nickName)
        {
            try
            {
                using (DLULNEntities db = new DLULNEntities())
                {
                    return db.Accounts.SingleOrDefault(acc => acc.Nickname_s == nickName);
                }
            }
            catch {
                return null;
            }
        }

        public static Account Single(Guid accountID)
        {
            try
            {
                using (DLULNEntities db = new DLULNEntities())
                {
                    return db.Accounts.SingleOrDefault(acc => acc.AccountID_u == accountID);
                }
            }
            catch 
            {
                return null;
            }
        }

        public static int Add(Account account)
        {
            try
            {
                DLULNEntities entities = new DLULNEntities();
                if (entities.Accounts.Where(acc => acc.Email_s.ToLower().CompareTo(account.Email_s.Trim().ToLower()) == 0).Count() > 0)
                {
                    return -1; // This email has already used
                }
                if (entities.Accounts.Where(acc => acc.Nickname_s.ToLower().CompareTo(account.Nickname_s.Trim().ToLower()) == 0).Count() > 0)
                {
                    return 2; // Nickname đã có
                }
                
                entities.AddToAccounts(account);
                IDNumber idNumber = entities.IDNumbers.SingleOrDefault(i => i.IDNumberID_i == account.IDNumberID_i);
                idNumber.IsUse_b = true;
                if (entities.SaveChanges() > 0)
                {
                    return 1; // Insert account successful
                }

                return 0; // Error occur
            }
            catch
            {
                return 0; // Error occur
            }
        }

        public static int Delete(Guid accountID)
        {
            using (DLULNEntities db = new DLULNEntities())
            {
                Account account = Single(accountID);
                if (account != null)
                {
                    db.Accounts.DeleteObject(account);
                    if (db.SaveChanges() > 0)
                    {
                        return 1; // Success
                    }
                    else
                    {
                        return 0; // Not success
                    }
                }

                return -1; // Not exist
            }
        }

        public static int Update(Account account)
        {
            try
            {
                DLULNEntities entities = new DLULNEntities();
                Account orginal = entities.Accounts.Where(acc => acc.Email_s.ToLower().CompareTo(account.Email_s.Trim().ToLower()) == 0).FirstOrDefault();
                if (orginal == null)
                {
                    return -1; // Don't exist this account
                }

                entities.ApplyCurrentValues(orginal.EntityKey.EntitySetName, account);
                //Banned lớp học
                if (account.IsBanned_b == true)
                {
                    foreach (Course course in account.Courses)
                    {
                        course.IsBanned_b = true;
                    }
                }
                if (entities.SaveChanges() > 0)
                {
                    return 1; // Update account successful
                }

                return 0; // Error occur
            }
            catch
            {
                return 0; // Error occur
            }
        }

        public static List<Account> SearchByName(Guid curUserID,string firstName,string lastName, int page, int numberOfItemPerPage, ref int totalItems)
        {
            try
            {
                IQueryable<Account> result;
                using (DLULNEntities db = new DLULNEntities())
                {
                    result = db.Accounts.Where(acc=>acc.AccountID_u != curUserID)
                                        .Where(acc => acc.FirstName_s.Contains(firstName))
                                        .Where(acc=>acc.LastName_s.Contains(lastName))
                                        .OrderBy(acc => acc.FirstName_s);
                    return GetPager(result, page, numberOfItemPerPage, ref totalItems);
                }
            }
            catch 
            {
                return null;   
            }
        }

        public static List<Account> GetPager(IQueryable<Account> accounts, int page, int numberOfItemPerPage, ref int totalItems)
        {
            totalItems = accounts.Count();
            if (page < 1)
            {
                page = 1;
            }

            return accounts.Skip((page - 1) * numberOfItemPerPage).Take(numberOfItemPerPage).ToList();
        }

        /// <summary>
        /// Update avatar
        /// </summary>
        /// <param name="accountID"></param>
        /// <param name="newFilePath"></param>
        /// <returns></returns>
        public static int UpdateAvatar(Guid accountID ,string newFilePath)
        {
            try
            {
                using (DLULNEntities db = new DLULNEntities())
                {
                    Account currentAccount = db.Accounts.SingleOrDefault(acc => acc.AccountID_u == accountID);
                    if (currentAccount == null)
                    {
                        return 0;
                    }
                    else
                    {
                        currentAccount.Avatar_s = newFilePath;
                        if (db.SaveChanges() > 0)
                        {
                            return 1;
                        }
                        else
                        {
                            return 101;
                        }
                    }
                }
            }
            catch 
            {
                return 101;
            }
        }

        public static List<Account> SelectAccountIsFriendAndNotEnrollCourseYet(Guid accountID, Guid courseID)
        { 
            using (DLULNEntities db = new DLULNEntities())
            {
                List<Account> list1 = (from fr in db.Friends
                             where fr.AccountID_u == accountID &&
                                (from en in db.Enrollments
                                where en.CourseID_u == courseID && en.AccountID_u == fr.FriendAccountID_u
                                select en).Count() == 0
                             from acc in db.Accounts
                                    where acc.AccountID_u == fr.FriendAccountID_u
                                    select acc).ToList();

                List<Account> list2 = (from fr in db.Friends
                                       where fr.FriendAccountID_u == accountID &&
                                          (from en in db.Enrollments
                                           where en.CourseID_u == courseID && en.AccountID_u == fr.AccountID_u
                                           select en).Count() == 0
                                       from acc in db.Accounts
                                       where acc.AccountID_u == fr.AccountID_u
                                       select acc).ToList();

                list1.AddRange(list2);
                return list1;
            }
        }

        /// <summary>
        /// Get all account that are not admin
        /// </summary>
        /// <param name="page"></param>
        /// <param name="itemsPerPage"></param>
        /// <param name="totalItems"></param>
        /// <returns></returns>
        public static List<Account> Pager(int page, int itemsPerPage, ref int totalItems)
        { 
            using (DLULNEntities db = new DLULNEntities())
            {
                IQueryable<Account> accounts = (from acc in db.Accounts                                               
                                               from ur in db.UserRoles
                                               where ur.AccountID_u != acc.AccountID_u
                                               && ur.RoleID_u == db.Roles.Where(r => r.Name_s == "Admin").Select(r => r.RoleID_u).FirstOrDefault()
                                               select acc).OrderBy(a => a.Nickname_s);
                return GetPager(accounts, page, itemsPerPage, ref totalItems);
            }
        }
    }
}
